package com.gin.kotlin.no_gay_alliance.worker

import android.content.Context
import android.util.Log
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.gin.kotlin.no_gay_alliance.app.App
import com.gin.kotlin.no_gay_alliance.argument.ReplyListArgument
import com.gin.kotlin.no_gay_alliance.argument.ReplyListArgument.Companion.MAX_PAGE
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTask.Status
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTask.Type
import com.gin.kotlin.no_gay_alliance.database.entity.ReplyHistoryTaskLog
import com.gin.kotlin.no_gay_alliance.provider.ngaphp.ReplyListProvider
import java.io.InterruptedIOException
import java.net.SocketException
import java.net.UnknownHostException
import java.time.ZonedDateTime
import java.util.concurrent.TimeUnit

/**
 * 回复历史，监控类任务
 * @constructor
 */
class ReplyHistoryTaskMonitorWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    private val dao = App.INSTANCE.database.replyHistoryTaskDao()
    private val logDao = App.INSTANCE.database.replyHistoryTaskLogDao()

    override fun doWork(): Result {
        val list = dao.list()
            ?.filter { it.type == Type.MONITOR && it.status == Status.IN_PROCESS }
            ?: return success()

        Log.i(TAG, "回复历史任务 - 自动监控")
        list.forEach { task ->
            // 请求最新的两页
            val page = task.totalPage.takeIf { it > 0 } ?: MAX_PAGE
            try {
                // 请求最新页
                val argument = ReplyListArgument(ReplyListArgument.Type.LIST, topicId = task.topicId, page = page, html = true)
                val body = ReplyListProvider.getInstance().execute(argument, ignoreCache = true)
                // 请求次新页
                ReplyListProvider.getInstance().execute(argument.copy(page = body.page - 1), ignoreCache = true)
                // 如果任务结束，修改状态，如果未结束则进度+1
                val completed = body.page == MAX_PAGE
                task.status = if (completed) Status.COMPLETED else task.status
                task.totalPage = body.totalPage ?: task.totalPage
                task.updatedTime = ZonedDateTime.now()
                dao.update(task)

                // 记录日志
                val msg = if (completed) "，任务已完成" else ""
                val log = ReplyHistoryTaskLog(id = 0, taskId = task.id, code = 200, message = "第 $page 页，请求成功$msg", timestamp = ZonedDateTime.now())
                logDao.add(log)
            } catch (e: Exception) {
                val msg = "${e.javaClass.simpleName}: ${e.localizedMessage}"
                var log = ReplyHistoryTaskLog(taskId = task.id)
                val warnMessage = "第 $page 页，请求异常，即将重试: $msg"
                when (e) {
                    is InterruptedIOException -> log = log.copy(code = 401, message = warnMessage)
                    is UnknownHostException -> log = log.copy(code = 401, message = warnMessage)
                    is SocketException -> log = log.copy(code = 401, message = warnMessage)
                    else -> {
                        log = log.copy(code = 400, message = "第 $page 页，请求失败，任务已停止: $msg")
                        dao.setStatus(task.id, Status.ERROR)
                        e.printStackTrace()
                    }
                }
                logDao.add(log)
            }
        }
        return success()

    }


    private fun success(delayMinutes: Long = 5): Result {
        start(delayMinutes)
        return Result.success()
    }

    companion object {
        private val TAG = ReplyHistoryTaskMonitorWorker::class.java.simpleName

        @JvmStatic
        fun start(delayMinutes: Long = 5) {
            val manager = WorkManager.getInstance(App.INSTANCE)
            // 清空相同任务
            manager.cancelAllWorkByTag(ReplyHistoryTaskMonitorWorker::class.java.name)
            // 构造任务请求
            // 任务限制：必须联网
            val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
            // 一次性任务
            val workRequest = OneTimeWorkRequest.Builder(ReplyHistoryTaskMonitorWorker::class.java).setConstraints(constraints)
                // 执行延迟
                .setInitialDelay(delayMinutes, TimeUnit.MINUTES)
                // 重试策略
                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS).build()
            // 提交任务
            manager.enqueue(workRequest)
        }

    }
}